use std::collections::HashMap;
use anyhow::Error;
use crate::context::certificate::get_certificate_context;
use crate::{AppResult, get_random_string, get_timestamp};
use axum::extract::{Query};
use axum::http::header;
use axum::response::{IntoResponse, Response};
use const_format::concatcp;
use openssl::base64::encode_block;
use openssl::hash::MessageDigest;
use openssl::pkey::Private;
use openssl::sign::Signer;
use quick_xml::se::to_string;
use serde::{Deserialize, Serialize};
use tracing::debug;

pub const SERVER_UID: &str = "vicro";
const LEASE_CONTENT: &str = concatcp!("4102415999000:", SERVER_UID);
pub fn registry(app: axum::Router) -> axum::Router {
    app.route(
        "/rpc/obtainTicket.action",
        axum::routing::get(obtain_ticket),
    )
    .route("/rpc/ping.action", axum::routing::get(ping))
    .route(
        "/rpc/prolongTicket.action",
        axum::routing::get(prolong_ticket),
    )
    .route(
        "/rpc/releaseTicket.action",
        axum::routing::get(release_ticket),
    )
}
struct SignXml<'a, T>{
    content:T,
    private_key:&'a openssl::pkey::PKey<Private>,
    server_child_crt:&'a openssl::x509::X509,
}

impl<'a,T> IntoResponse for SignXml<'a, T>
where
    T: Serialize,
{
    fn into_response(self) -> Response {
        // 尝试将结构体序列化为 XML 字符串
        match to_string(&self.content) {
            Ok(xml) => {
                let sign_data = sign_content(xml.clone(), &self.private_key, MessageDigest::sha1()).unwrap_or("".to_string());
                let certificate_base64 = encode_block(&self.server_child_crt.to_der().unwrap());
                let signed_xml = format!("<!-- SHA1withRSA-{}-{} -->\n{}", sign_data, certificate_base64, xml);
                    (
                        // 设置正确的 Content-Type
                        [(header::CONTENT_TYPE, "application/xml; charset=utf-8")],
                        signed_xml,
                    )
                    .into_response()},
            Err(e) => (
                // 序列化失败时返回 500 错误
                axum::http::StatusCode::INTERNAL_SERVER_ERROR,
                [(header::CONTENT_TYPE, "text/plain")],
                format!("Failed to serialize to XML: {}", e),
            )
                .into_response(),
        }
    }
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[serde(rename = "ObtainTicketResponse")]
pub struct ObtainTicketResponse {
    /// 需要执行的动作，通常为 "NONE" 表示无需额外操作
    #[serde(rename = "action")]
    pub action: String,

    /// 确认时间戳，由服务器生成，用于验证请求的有效性和及时性
    #[serde(rename = "confirmationStamp")]
    pub confirmation_stamp: String,

    /// 租约签名，用于验证服务器的合法性和权威性
    #[serde(rename = "leaseSignature")]
    pub lease_signature: String,

    /// 响应消息，通常为空，只在出现错误时包含错误信息
    #[serde(rename = "message")]
    pub message: String,

    /// 延长周期（毫秒），表示多久后可以申请延长许可证
    #[serde(rename = "prolongationPeriod")]
    pub prolongation_period: String,

    /// 响应码，"OK" 表示成功，其他值表示各种错误情况
    #[serde(rename = "responseCode")]
    pub response_code: String,

    /// 加密盐值，从请求中原样返回，用于增强通信安全性
    #[serde(rename = "salt")]
    pub salt: String,

    /// 服务器租约内容，包含过期时间和服务器标识
    #[serde(rename = "serverLease")]
    pub server_lease: String,

    /// 服务器唯一标识符，用于标识许可证服务器实例
    #[serde(rename = "serverUid")]
    pub server_uid: String,

    /// 许可证凭证的唯一标识符，由服务器随机生成
    #[serde(rename = "ticketId")]
    pub ticket_id: String,

    /// 许可证凭证属性，包含持有者、类型和元数据等信息
    #[serde(rename = "ticketProperties")]
    pub ticket_properties: String,

    /// 验证截止时间（毫秒），-1 表示无截止时间
    #[serde(rename = "validationDeadlinePeriod")]
    pub validation_deadline_period: String,

    /// 验证周期（毫秒），表示多久后需要重新验证
    #[serde(rename = "validationPeriod")]
    pub validation_period: String,
}
fn sign_content(
    content: String,
    private_key: &openssl::pkey::PKey<Private>,
    sign_algorithm: MessageDigest,
) -> AppResult<String> {
    let mut signer = Signer::new(sign_algorithm, private_key)?;
    signer.update(content.as_bytes())?;
    Ok(encode_block(&signer.sign_to_vec()?))
}
async fn get_confirmation_stamp(machine_id: &str) -> AppResult<String> {
    debug!("生成确认时间戳 - 机器ID: {}", machine_id);
    let timestamp = get_timestamp();
    let content_sign = format!("{}:{}", timestamp, machine_id);
    let cache = get_certificate_context().await.cache();
    let private_key = cache.get_private_key();
    let signature = sign_content(content_sign, private_key, MessageDigest::sha1())?;
    let certificate_base64 = encode_block(&cache.get_server_child_cet().to_der()?);
    Ok(format!(
        "{}:{}:SHA1withRSA:{}:{}",
        timestamp, machine_id, signature, certificate_base64
    ))
}
async fn get_lease_signature() -> AppResult<String> {
    let cache = get_certificate_context().await.cache();
    let private_key = cache.get_private_key();
    let sign = sign_content(
        LEASE_CONTENT.to_string(),
        private_key,
        MessageDigest::sha512(),
    )?;
    let code_crt = cache.get_code_cet();
    let certificate_base64 = encode_block(&code_crt.to_der()?);
    Ok(format!("SHA512withRSA-{}-{}", sign, certificate_base64))
}
async fn obtain_ticket(Query(map): Query<HashMap<String, String>>) -> AppResult<impl IntoResponse> {

    let host_name = map.get("hostName").ok_or(Error::msg("缺少参数 hostName"))?;
    let machine_id = map.get("machineId").ok_or(Error::msg("缺少参数 machineId"))?;
    let salt = map.get("salt").ok_or(Error::msg("缺少参数 salt"))?;
    debug!(
        "接收到获取许可证凭证请求 - 主机: {}, 机器ID: {}",
        host_name, machine_id
    );
    let confirmation_stamp = get_confirmation_stamp(machine_id).await?;
    let lease_signature = get_lease_signature().await?;
    let response = ObtainTicketResponse {
        action: "NONE".to_string(),
        confirmation_stamp,
        lease_signature,
        message: " ".to_string(),
        prolongation_period: "600000".to_string(),
        response_code: "OK".to_string(),
        salt: salt.parse()?,
        server_lease: LEASE_CONTENT.to_string(),
        server_uid: SERVER_UID.to_string(),
        ticket_id: get_random_string::<20>()?.to_string(),
        ticket_properties: format!(
            "licensee={}\tlicenseeType=5\tmetadata=0120211231PSAN000005",
            host_name
        ),
        validation_deadline_period: "-1".to_string(),
        validation_period: "600000".to_string(),
        ..ObtainTicketResponse::default()
    };
    debug!("返回获取许可证凭证结果 - {:?}", response);
    let xml = SignXml{
        content: response,
        private_key: get_certificate_context().await.cache().get_private_key(),
        server_child_crt: get_certificate_context().await.cache().get_server_child_cet(),
    };
    Ok(xml.into_response())
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[serde(rename = "PingResponse")]
pub struct PingResponse {
    /// 需要执行的动作，通常为 "NONE"
    #[serde(rename = "action")]
    pub action: String,

    /// 确认时间戳，用于验证请求的有效性
    #[serde(rename = "confirmationStamp")]
    pub confirmation_stamp: String,

    /// 租约签名，用于验证服务器的合法性
    #[serde(rename = "leaseSignature")]
    pub lease_signature: String,

    /// 响应消息，通常为空
    #[serde(rename = "message")]
    pub message: String,

    /// 响应码，"OK" 表示成功
    #[serde(rename = "responseCode")]
    pub response_code: String,

    /// 加密盐值，从请求中原样返回
    #[serde(rename = "salt")]
    pub salt: String,

    /// 服务器租约内容
    #[serde(rename = "serverLease")]
    pub server_lease: String,

    /// 服务器唯一标识符
    #[serde(rename = "serverUid")]
    pub server_uid: String,

    /// 验证截止时间，-1 表示无截止时间
    #[serde(rename = "validationDeadlinePeriod")]
    pub validation_deadline_period: String,

    /// 验证周期，表示多久后需要重新验证
    #[serde(rename = "validationPeriod")]
    pub validation_period: String,
}
async fn ping(Query(map): Query<HashMap<String, String>>) -> AppResult<impl IntoResponse> {
    let host_name = map.get("hostName").ok_or(Error::msg("缺少参数 hostName"))?;
    let machine_id = map.get("machineId").ok_or(Error::msg("缺少参数 machineId"))?;
    let salt = map.get("salt").ok_or(Error::msg("缺少参数 salt"))?;
    debug!(
        "接收到获取许可证凭证请求 - 主机: {}, 机器ID: {}",
        host_name, machine_id
    );
    let confirmation_stamp = get_confirmation_stamp(machine_id).await?;
    let lease_signature = get_lease_signature().await?;
    let response = PingResponse {
        action: "NONE".to_string(),
        confirmation_stamp,
        lease_signature,
        message: "".to_string(),
        response_code: "OK".to_string(),
        salt: salt.parse()?,
        server_lease: LEASE_CONTENT.to_string(),
        server_uid: SERVER_UID.to_string(),
        validation_deadline_period: "-1".to_string(),
        validation_period: "600000".to_string(),
        ..Default::default()
    };
    debug!("返回获取许可证凭证结果 - {:?}", response);
    let xml = SignXml{
        content: response,
        private_key: get_certificate_context().await.cache().get_private_key(),
        server_child_crt: get_certificate_context().await.cache().get_server_child_cet(),
    };
    Ok(xml.into_response())
}

async fn prolong_ticket(query: Query<HashMap<String, String>>) -> AppResult<impl IntoResponse> {
    debug!("接收到延长许可证请求");
    ping(query).await
}
async fn release_ticket(query: Query<HashMap<String, String>>) -> AppResult<impl IntoResponse> {
    debug!("接收到释放许可证请求");
    ping(query).await
}

#[cfg(test)]
mod tests {
    use super::*;
    #[tokio::test]
    async fn test_get_confirmation_stamp() {
        let stamp = get_lease_signature().await.unwrap();
        println!("{}", stamp);
    }
}